use crate::{config::Name, Config};

use super::Class;

#[derive(Clone)]
pub struct Options<'a> {
	pub(crate) cfg: &'a Config,
}

pub struct FmtInterface<'a> {
	class: &'a Class,
	options: Options<'a>,
	this_: Name<'a>,
	super_: Name<'a>,
}
impl<'a> FmtInterface<'a> {
	pub fn new(class: &'a Class, options: Options<'a>) -> Option<Self> {
		Some(Self {
			class,
			this_: options.cfg.name(&class.this_),
			super_: options.cfg.name(&class.super_),
			options,
		})
	}
}
impl<'a> std::fmt::Display for FmtInterface<'a> {
	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
		let this_ = &self.this_.to_rust();
		let _super_ = &self.super_.to_rust();
		let snake = self.this_.to_snake();
		let class_fun = snake.clone() + "_class";
		f.write_fmt(format_args!(
			r##"
// This file has been automatically generated by `jnim` from `{this_}.class`.
// DO NOT EDIT

use jnim::*;

{super_use}
{faces_use}

pub trait {this_}: AsRef<JObject> {interface_list} {{
{constant_fields}
	fn {snake}_class(env: Option<&JEnv>) -> Option<JClassID> {{
		const NAME: &'static [u8] = b"{java_full}\0";
		static CACHE: CachedID = CachedID::new();
		CACHE.get(|| JEnv::env(env)?.find_class(NAME))
	}}
	{fields}
	{fields_static}
	{static_method}
	{virtual_method}
}}

pub struct {this_}Object {{
	__object: JObject,
}}
impl {this_} for {this_}Object {{}}
impl JNameMaker for {this_}Object {{
	const JAVA_PATH: &'static [u8] = b"{java_full}\0";
}}
impl JPlainMarker for {this_}Object {{
	fn class(env: Option<&JEnv>) -> Option<JClassID> {{
		static CACHE: CachedID = CachedID::new();
		CACHE.get(|| JEnv::env(env)?.find_class(Self::JAVA_PATH))
	}}
}}
impl core::ops::Deref for {this_}Object {{
	type Target = JObject;
	fn deref(&self) -> &Self::Target {{
		&self.__object
	}}
}}
impl AsRef<JObject> for {this_}Object {{
	fn as_ref(&self) -> &JObject {{
		&self.__object
	}}
}}

{interface_impl}

#[test]
fn test_type_zero() {{
	assert_eq!(0, std::mem::size_of::<{this_}Object>());
}}

"##,
			super_use = self.super_.fmt_use(),
			java_full = self.this_.as_java(),
			faces_use = self.class.fmt_faces_use(false),
			interface_list = self.class.fmt_faces_ext(),
			interface_impl = self.class.fmt_faces_impl(&(this_.to_string() + "Object"), false),
			constant_fields = self.class.fmt_consts(""),
			fields = self.class.fmt_fields("", &class_fun, self.options.cfg),
			fields_static = self.class.fmt_fields_static("", &class_fun, self.options.cfg),
			virtual_method = self.class.fmt_methods("", &class_fun, self.options.cfg),
			static_method = self.class.fmt_methods_static("", &class_fun, self.options.cfg),
		))?;
		Ok(())
	}
}
